package com.xsoft.navigation.ble;

import android.util.Log;

import com.ficat.easyble.BleDevice;
import com.ficat.easyble.gatt.bean.CharacteristicInfo;
import com.ficat.easyble.gatt.bean.ServiceInfo;
import com.ficat.easyble.gatt.callback.BleConnectCallback;
import com.ficat.easyble.gatt.callback.BleNotifyCallback;
import com.ficat.easyble.scan.BleScanCallback;
import com.xsoft.common.util.SharePrefUtils;
import com.xsoft.navigation.BuildConfig;
import com.xsoft.navigation.MyApplication;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * created by zhangkai on 2021/7/22
 * email: 405547628@qq.com
 * desc:
 */
public class BleManager {
    private static final String TAG = BleManager.class.getSimpleName();
    private static final String KEY_LAT = "lat";
    private static final String KEY_LON = "lon";
    private static final String KEY_POSITION = "position";//惯性导航是否生效
    private static final String KEY_SPEED = "speed";//陈广平新增：当前速度
    private static final String KEY_ALT = "alt";//陈广平新增：当前海拔
    private static final String KEY_TIME = "time";//陈广平新增：当前时间


    private static final BleManager ourInstance = new BleManager();
    private com.ficat.easyble.BleManager bleManager;
    private BleDevice connectedBleDevice;
    private List<String> locationData = new ArrayList<>();

    public static BleManager getInstance() {
        return ourInstance;
    }

    private BleManager() {
        initBleManager();
    }

    private void initBleManager() {
        com.ficat.easyble.BleManager.ScanOptions scanOptions = com.ficat.easyble.BleManager.ScanOptions
                .newInstance()
                .scanPeriod(8000)
                .scanDeviceName(null);

        com.ficat.easyble.BleManager.ConnectOptions connectOptions = com.ficat.easyble.BleManager.ConnectOptions
                .newInstance()
                .connectTimeout(12000);
        bleManager = com.ficat.easyble.BleManager.getInstance()
                .setScanOptions(scanOptions)
                .setConnectionOptions(connectOptions)
                .setLog(BuildConfig.DEBUG, "ble")
                .init(MyApplication.context);
    }

    public void startScan(OnBleScanListener listener) {
        if (bleManager == null) {
            initBleManager();
        }
        if (listener != null && connectedBleDevice != null) {
            listener.onLeScan(connectedBleDevice);
        }
        bleManager.startScan(new BleScanCallback() {
            @Override
            public void onLeScan(BleDevice device, int rssi, byte[] scanRecord) {
                if (listener != null) {
                    listener.onLeScan(device);
                }
            }

            @Override
            public void onStart(boolean startScanSuccess, String info) {
                if (listener != null) {
                    listener.onStart(startScanSuccess);
                }
            }

            @Override
            public void onFinish() {
                if (listener != null) {
                    listener.onEnd();
                }
            }
        });
    }

    public void stopScan() {
        if (bleManager != null) {
            bleManager.stopScan();
        }
    }

    public void connectAndRead(BleDevice device, OnBleConnectListener listener) {
        if (bleManager == null) {
            initBleManager();
        }
        bleManager.connect(device.address, new BleConnectCallback() {
            @Override
            public void onStart(boolean startConnectSuccess, String info, BleDevice device) {

            }

            @Override
            public void onConnected(BleDevice device) {
                connectedBleDevice = device;
                if (listener != null) {
                    listener.onConnected(device);
                }
                Map<ServiceInfo, List<CharacteristicInfo>> infoListMap = bleManager.getDeviceServices(device);
                Set<ServiceInfo> infos = infoListMap.keySet();
                for (ServiceInfo info : infos) {
                    List<CharacteristicInfo> characteristicInfos = infoListMap.get(info);
                    for (CharacteristicInfo info1 : characteristicInfos) {
                        if (info1.notify) {
                            Log.i(TAG, info1.uuid);
                            bleManager.notify(device, info.uuid, info1.uuid, new BleNotifyCallback() {
                                @Override
                                public void onCharacteristicChanged(byte[] data, BleDevice device) {
                                    try {
                                        String str = new String(data, "ascii");
                                        Log.i(TAG, "onCharacteristicChanged " + str);
                                        parseCharacteristic(str);
                                        if (listener != null) {
                                            listener.updateLocation(getRecordLat(), getRecordLon());
                                        }
                                        /*if (TextUtils.equals(str, "A")) {
                                            locationData.clear();
                                        }
                                        locationData.add(str);
                                        if (locationData.size() == 5 && TextUtils.equals(locationData.get(0), "A")) {
                                            String lat = locationData.get(1);
                                            String latDir = locationData.get(2);
                                            String lon = locationData.get(3);
                                            String lonDir = locationData.get(4);
                                            String latitude = String.valueOf(parseLatitude(lat, latDir));
                                            String longitude = String.valueOf(parseLongitude(lon, lonDir));
                                            SharePrefUtils.saveValue(KEY_LAT, latitude);
                                            SharePrefUtils.saveValue(KEY_LON, longitude);
                                            if (listener != null) {
                                                listener.updateLocation(latitude, longitude);
                                            }
                                        }*/
                                    } catch (UnsupportedEncodingException e) {
                                        e.printStackTrace();
                                    }
                                }

                                @Override
                                public void onNotifySuccess(String notifySuccessUuid, BleDevice device) {

                                }

                                @Override
                                public void onFailure(int failCode, String info, BleDevice device) {

                                }
                            });
                            break;
                        }
                    }
                }
            }

            @Override
            public void onDisconnected(String info, int status, BleDevice device) {
                connectedBleDevice = null;
            }

            @Override
            public void onFailure(int failCode, String info, BleDevice device) {
            }
        });
    }

    private void parseCharacteristic(String characteristic) {
        if (characteristic.startsWith("LAT=")) {
            String[] lat = characteristic.substring("LAT=".length()).split(",");
            if (lat.length == 2) {
                String latitude = String.valueOf(parseLatitude(lat[0], lat[1]));
                SharePrefUtils.saveValue(KEY_LAT, latitude);
            }
        } else if (characteristic.startsWith("LNG=")) {
            String[] lng = characteristic.substring("LNG=".length()).split(",");
            if (lng.length == 2) {
                String longitude = String.valueOf(parseLongitude(lng[0], lng[1]));
                SharePrefUtils.saveValue(KEY_LON, longitude);
            }
        } else if (characteristic.startsWith("POSITION=")) {
            int position = Integer.valueOf(characteristic.substring("POSITION=".length()));
            SharePrefUtils.saveValue(KEY_POSITION, position);
        } else if (characteristic.startsWith("TIME=")) {

        } else if (characteristic.startsWith("ALT=")) {

        } else if (characteristic.startsWith("SPEED=")) {

        }
    }

    private double parseLatitude(String lat, String orientation) {
        double latitude = 0.0;
        if (lat != null && orientation != null && !lat.equals("") && !orientation.equals("")) {
            double temp1 = Double.parseDouble(lat);
            double temp2 = Math.floor(temp1 / 100);
            double temp3 = (temp1 / 100 - temp2) / 0.6;
            if (orientation.equals("S")) {
                latitude = -(temp2 + temp3);
            } else if (orientation.equals("N")) {
                latitude = (temp2 + temp3);
            }
        }
        return latitude;
    }

    private double parseLongitude(String lon, String orientation) {
        double longitude = 0.0;
        if (lon != null && orientation != null && !lon.equals("") && !orientation.equals("")) {
            double temp1 = Double.parseDouble(lon);
            double temp2 = Math.floor(temp1 / 100);
            double temp3 = (temp1 / 100 - temp2) / 0.6;
            if (orientation.equals("W")) {
                longitude = -(temp2 + temp3);
            } else if (orientation.equals("E")) {
                longitude = (temp2 + temp3);
            }
        }
        return longitude;
    }

    public String getRecordLat() {
        return SharePrefUtils.getStringValue(KEY_LAT, null);
    }

    public String getRecordLon() {
        return SharePrefUtils.getStringValue(KEY_LON, null);
    }

    /**
     * 判断惯性导航是否生效，即惯性gps数据是否有效
     *
     * @return
     */
    public boolean isGpsOn() {
        return SharePrefUtils.getIntValue(KEY_POSITION) == 2;
    }

    public void destroy() {
        if (bleManager != null) {
            bleManager.destroy();
            bleManager = null;
        }
    }

    public interface OnBleScanListener {
        void onStart(boolean startScanSuccess);

        void onEnd();

        void onLeScan(BleDevice device);
    }

    public interface OnBleConnectListener {
        void onConnected(BleDevice device);

        void updateLocation(String lat, String lon);
    }
}
